//
//  HTTPTool.m
//  GuChat
//
//  Created by iBenz on 14-10-19.
//  Copyright (c) 2014年 Guzhi Tech. All rights reserved.
//

#import "HTTPTool.h"
#import <AFNetworking/AFNetworking.h>
#import <CommonCrypto/CommonCrypto.h>
#include <sys/sysctl.h>
#import "NSString+Hash.h"

static NSString *const kAESKey = @"Q(MEc*6|~rCnwk0}";
static NSString *const kAESIv = @"A-16-Byte-String";
static NSString *const kHTTPSignKey = @"QMIIEIjANBgkqhkiG9w";

NSString *Platform() {
    static NSString *platform = nil;
    if (!platform) {
        size_t size;
        sysctlbyname("hw.machine", NULL, &size, NULL, 0);
        char *machine = malloc(size);
        sysctlbyname("hw.machine", machine, &size, NULL, 0);
        platform = [NSString stringWithUTF8String:machine];
        free(machine);
    }
    return platform;
}
NSString *MD5(NSString *string) {
    const char *str = string.UTF8String;
    uint8_t buffer[CC_MD5_DIGEST_LENGTH];
    CC_MD5(str, (CC_LONG)strlen(str), buffer);
    NSMutableString *strM = [NSMutableString string];
    for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
        [strM appendFormat:@"%02x", buffer[i]];
    }
    return strM;
}
NSString *Encoding(NSString *urlStr) {
    if (([[[UIDevice currentDevice] systemVersion] compare:@"9.0" options:NSNumericSearch] != NSOrderedAscending)) { // iOS9.0+
        return [urlStr stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    }
    else {
        return [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    }
}
NSString *HttpSignature(NSDictionary *parameters)/*, NSString *signKey)*/ {
    NSArray *keyArray = [parameters.allKeys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
        NSComparisonResult compar = [obj1 compare:obj2];
        return compar;
    }];
    
    NSMutableArray *arr = [NSMutableArray array];
    for (NSString *key in keyArray) {
        [arr addObject:[NSString stringWithFormat:@"%@=%@", key, parameters[key]?:@""]];
    }
    [arr addObject:[NSString stringWithFormat:@"key=%@", kHTTPSignKey]];
    NSString *sortString = [arr componentsJoinedByString:@"&"];
    //NSData *data = [RSAEncryptor encryptData:[sortString dataUsingEncoding:NSUTF8StringEncoding] publicKey:kRSA2PrivateKey];
    //return [data base64EncodedStringWithOptions:0];;
    return MD5(sortString);
}
NSString *URLComponents(NSDictionary *parameters) {
    NSMutableArray *paramPair = [NSMutableArray array];
    for (NSString *key in parameters.allKeys) {
        [paramPair addObject:[NSString stringWithFormat:@"%@=%@", key, parameters[key]?:@""]];
    }
    
    return [paramPair componentsJoinedByString:@"&"];
}
NSString *AES128Encrypt(NSString *plain) {
    return [plain AES128EncryptWithKey:kAESKey iv:kAESIv];
}
NSString *AES128Decrypt(NSString *cipher) {
    return [cipher AES128DecryptWithKey:kAESKey iv:kAESIv];
}
NSString *AES256Signature(NSDictionary *parameters) {
    NSString *sign = HttpSignature(parameters);
    NSArray *arr = [[URLComponents(parameters) componentsSeparatedByString:@"&"] arrayByAddingObject:[NSString stringWithFormat:@"sign=%@", sign]];
    NSString *aes = [arr componentsJoinedByString:@"&"];
    //return [aes AES256EncryptWithKey:kAESKey];
    return AES128Encrypt(aes);//[aes AES128EncryptWithKey:kAESKey iv:kAESIv];
}
NSDictionary *FinalParameters(NSDictionary *parameters) {
    //NSMutableDictionary *param = [NSMutableDictionary dictionaryWithDictionary:parameters];
    //[param setValue:AES256Signature(parameters) forKey:@"r"];
    //return param;
    NSString *aes = AES256Signature(parameters);
    return @{@"r":aes?:@""};
}

static NSString *const HTTPSession = @"sessionManager";
static NSString *const HTTPTask    = @"task";

@interface HTTPTool ()

@property(nonatomic, strong) AFHTTPSessionManager *sessionManager;

@end

@implementation HTTPTool

+ (instancetype)shareInstance
{
    static HTTPTool *helper;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        helper = [[self alloc] init];
    });
    
    // FIXME:: update token and uid in every http require
    // 可以上子模块上实现请求头的相关设置，这样HTTPTool就完全解偶了
    [self dispatchHeaderFields:helper.sessionManager];
    return helper;
}

+ (void)dispatchHeaderFieldsOnce:(AFHTTPSessionManager *)manager{}
+ (void)dispatchHeaderFields:(AFHTTPSessionManager *)manager {}

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.sessionManager = [AFHTTPSessionManager manager];
        self.sessionManager.responseSerializer.acceptableContentTypes = [NSSet setWithArray:@[@"application/json",@"text/html",@"text/json",@"text/plain",@"text/javascript",@"text/xml",@"image/*"]];
//        self.sessionManager.requestSerializer = [AFJSONRequestSerializer serializer];
//        self.sessionManager.requestSerializer = [AFHTTPRequestSerializer serializer];
        [self.sessionManager.requestSerializer setValue:@"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
        
        // add extend info
        [self.class dispatchHeaderFieldsOnce:self.sessionManager];
    }
    return self;
}

+ (NSURLSessionDataTask *)GET:(NSString *)httpUrl parameters:(NSDictionary *)parameters complete:(HTTPComplete)complete {
    //parameters = FinalParameters(parameters?:@{});
    NSString *r = AES256Signature(parameters?:@{});
    parameters = @{@"r":r?:@""};
    AFHTTPSessionManager* sm = [self.shareInstance sessionManager];
    NSURLSessionDataTask *task = [sm GET:Encoding(httpUrl) parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        [self processResult:responseObject complete:complete];
        NSLog(@"%@\n==>%@", [httpUrl stringByAppendingString:AES128Decrypt(r)], AES128Decrypt((NSString *)responseObject[@"r"]));
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        if (complete) {
            complete(error, nil);
        }
        NSLog(@"%@\n==>%@", [httpUrl stringByAppendingString:AES128Decrypt((NSString *)parameters.allValues.firstObject)], [error localizedDescription]);
    }];
    return task;
}

+ (NSURLSessionDataTask *)POST:(NSString *)httpUrl parameters:(NSDictionary *)parameters formDatas:(NSArray<FormData*> *)formDatas complete:(HTTPComplete)complete {
    //parameters = FinalParameters(parameters?:@{});
    NSString *r = AES256Signature(parameters?:@{});
    parameters = @{@"r":r?r:@""};
    AFHTTPSessionManager* sm = [self.shareInstance sessionManager];
    NSURLSessionDataTask *task = [sm POST:Encoding(httpUrl) parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData>formData) {
        for (FormData *form in formDatas) {
            [formData appendPartWithFileData:form.data name:form.name fileName:form.fileName mimeType:form.mimeType];
        }
    } progress:nil success:^(NSURLSessionDataTask *task, id responseObject) {
        [self processResult:responseObject complete:complete];
        NSLog(@"%@\n==>%@", [httpUrl stringByAppendingString:AES128Decrypt(r)], AES128Decrypt((NSString *)responseObject[@"r"]));
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        if (complete) {
            complete(error, nil);
        }
        NSLog(@"%@\n==>%@", [httpUrl stringByAppendingString:AES128Decrypt((NSString *)parameters.allValues.firstObject)], [error localizedDescription]);
    }];
    return task;
}

+ (void)processResult:(id)responseObject complete:(HTTPComplete)complete {
    if (complete) {
        NSString *r = [(NSString *)responseObject[@"r"] AES128DecryptWithKey:kAESKey iv:kAESIv];
        //r = [r stringByReplacingOccurrencesOfString:@"\b" withString:@""];
        NSError *error = nil;
        NSDictionary *response = [NSJSONSerialization
                                 JSONObjectWithData:[r dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:&error];
        complete(error, response);
    }
}

@end

@implementation FormData
@end
